package vista;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.swing.JPanel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import controlador.ManejadorDeES;

import modelo.Modelo;
import modelo.abstraccionesGeometricas.Punto;
import modelo.funciones.Funcion;
import modelo.funciones.Redondear;
public class VistaGraficador extends JPanel implements ListSelectionListener, ActionListener {
	
	private Modelo modelo;
	private List<Funcion> funciones;
	private static double ESCALA = 1;
	private static int step = 33;
	private List<Funcion> funcionesEvaluadas = new ArrayList<Funcion>();
	private ManejadorDeES manejador = new ManejadorDeES();
	
	public VistaGraficador(Modelo modelo){
		this.setModelo(modelo);
		this.setFunciones(new ArrayList<Funcion>());
		super.setSize(500, 500);
	}
	
	private void dibujarLosEjes(Graphics g,int centroY,int centroX){
		
		int MasInfinitoX = (int)(this.getWidth()/2);
		int MasInfinitoY = (int)(this.getHeight()/2);
		
		g.setColor(Color.BLACK);
		g.drawLine(0,centroY,centroX*2,centroY);
		g.drawLine(centroX,0,centroX,centroY*2);
		for (int i = 1; i<MasInfinitoX; i++) {
			int x = obtenerPosicionX1(i,centroX);
			g.drawLine(x, centroY+8, x, centroY-8);
			g.drawString((new Double(Redondear.redondear(i*ESCALA))).toString(),x , centroY-10);
			int menosX = obtenerPosicionX1(-i,centroX);
			g.drawLine(menosX, centroY+8, menosX, centroY-8);
			g.drawString((new Double(Redondear.redondear(-i*ESCALA))).toString(),menosX , centroY-10);
			
		}
		for (int i = 1; i<MasInfinitoY; i++) {
			int y = obtenerPosicionY1(i,centroY);
			g.drawLine(centroX+8, y, centroX-8, y);
			g.drawString((new Double(Redondear.redondear(i*ESCALA))).toString(), centroX-10, y);
			int menosY = obtenerPosicionY1(-i,centroY);
			g.drawLine(centroX+8, menosY, centroX-8, menosY);
			g.drawString((new Double(Redondear.redondear(-i*ESCALA))).toString(), centroX-10, menosY);
		}
		
	}
	
	private int obtenerPosicionX(double x, int centroX) {
		return (int)(centroX + (x/ESCALA)*step);
	}
	
	private int obtenerPosicionY(double y, int centroY) {
		return (int)(centroY - (y/ESCALA)*step);
	}
	private int obtenerPosicionX1(double x, int centroX) {
		return (int)(centroX + x*step);
	}
	
	private int obtenerPosicionY1(double y, int centroY) {
		return (int)(centroY - y*step);
	}

	public List<Punto> evaluarFuncion(Funcion funcion) {
		List<Punto> vector = new ArrayList<Punto>();
		if (funcionesEvaluadas.contains(funcion)) {
			try{
				vector = manejador.cargarDesdeXML(funcion);
				return vector;
			}catch (Exception e){
				System.out.println(e.toString());
			}
		}
		else {
			for (double i = -100; i<100; i=i+0.01) {
				Punto punto = new Punto(i,funcion.evaluar(i));
				vector.add(punto);
			}
			try{
				manejador.guardarEnXML(vector, funcion);
				funcionesEvaluadas.add(funcion);
			}catch (Exception e){}
			return vector;
		}
		return vector;
	}
	
	public void graficarPuntos(Graphics g, List<Punto> puntos) {
		int centroX=(this.getSize().width)/2;
		int centroY=(this.getSize().height)/2;
		Iterator<Punto> it = puntos.iterator();
		Punto punto1 = it.next();
		while (it.hasNext()) {
			
			int x1,y1,x2,y2;
			try {
				Punto punto2 = it.next();
				x1 = obtenerPosicionX(punto1.getCoordenadaX(),centroX);
				y1 = obtenerPosicionY(punto1.getCoordenadaY(),centroY);
				x2 = obtenerPosicionX(punto2.getCoordenadaX(),centroX);
				y2 = obtenerPosicionY(punto2.getCoordenadaY(),centroY);
				g.drawLine(x1,y1,x2,y2);
				punto1 = punto2;
			}catch (Exception e) {}
		}
	}
	
	public void paintComponent(Graphics g) {
		
		super.paintComponent(g) ;
		int centroX=(this.getSize().width)/2;
		int centroY=(this.getSize().height)/2;
		
		g.setColor(Color.red);
		this.dibujarLosEjes(g,centroY,centroX);
		
		//si hay funciones en la lista las grafica
		if (!this.getModelo().getFunciones().isEmpty()){
			for (int j=0;j<this.getFunciones().size();j++){
				List<Punto> vector = evaluarFuncion(this.getFunciones().get(j));
				graficarPuntos(g,vector);
			}
		}
		
	}

	public void setFunciones(List<Funcion> f){
		this.funciones=f;
	}
	
	public List<Funcion> getFunciones(){
		return this.funciones;
	}  
	
	public void setModelo(Modelo modelo){
		this.modelo=modelo;
	}
	
	public Modelo getModelo(){
		return this.modelo;
	}
	
	public void valueChanged(ListSelectionEvent arg0) {
		if (!this.getModelo().getFunciones().isEmpty()){
		this.getFunciones().clear();
		VistaLista vistaLista=(VistaLista)arg0.getSource();
		int []vector=vistaLista.getSelectedIndices();
		for (int i=0;i<vector.length;i++)
		this.getFunciones().add((Funcion)this.getModelo().getFunciones().get(vector[i]));
		}
		this.repaint();
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource() instanceof BotonObservador) {
			BotonObservador boton = (BotonObservador)e.getSource();
			if (boton.getLabel().equals("Reducir"))
				VistaGraficador.ESCALA = VistaGraficador.ESCALA*10;
			if (boton.getLabel().equals("Ampliar"))
				VistaGraficador.ESCALA = VistaGraficador.ESCALA/10;
 
			this.repaint();
		}
	}
}
